/**
 * Definition of lazy container.
 *
 * \file lazy-container.hpp
 * \author tomby
 * \date 04-01-2009
 **/

/*  Copyright (C) 2009  Tomas 'tomby' Bily

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */


#ifndef __DBC_LAZY_CONTAINER__
#define __DBC_LAZY_CONTAINER__

namespace dbc 
{

  /***
   * Lazy container is linear container that has not stored data until
   * they are needed (read).
   * CB_TYPE needs to implement:
   *	bool update (Cache&, Range&)
   *	int size ()
   */

  template <typename TYPE, typename CB_TYPE>
  class LazyContainer
  {
  public:
    typedef boost::shared_ptr<LazyContainer> Ptr;
    typedef std::pair<int, int> Range;
    typedef std::vector<TYPE> CacheType;
    typedef boost::shared_ptr<CacheType> Cache;

  private:
    CB_TYPE*		cb;
    
  public:
    class iterator 
    {
    private:
      CB_TYPE*	cb;
      Cache	cache;
      Range	range;
      typename CacheType::iterator it;

    public:
      
      iterator ()
	: cb (NULL), range (-1, -1)
      { it = cache->end (); }

      iterator (CB_TYPE* icb)
	: cb (icb), cache (new CacheType)
      {
	range = std::pair<int,int> (-1, -1);
	cb->update (cache, range);
	it = cache->begin ();
      }

      inline void update ()
      {
	if (it != cache->end ())
	  return;

	if (cb->update (cache, range))
	  it = cache->begin ();
	else
	  {
	    cb = NULL;
	    range = Range (-1, -1);
	    it = cache->end ();
	  }
      }

      iterator& operator++ ()
      { update (); ++it; return *this; }

      iterator  operator++ (int)
      { iterator tmp = *this; ++it; return tmp; }

      bool operator== (const iterator& itr)
      { 
	if (cb != itr.cb)
	  return false;
	if (range != itr.range)
	  return false;
	if (it != itr.it)
	  return false;
	return true;
      }

      TYPE& operator* ()
      { return *it; }
    };

  public:
    LazyContainer ()
      : cb (NULL)
    {}

    LazyContainer (CB_TYPE* icb)
      : cb (icb)
    {}
    
    iterator begin ();
    iterator end ();
    
    int size ();
    CB_TYPE* get_cb ();
    void set_cb (CB_TYPE* icb);
  };

  /// Implementation

  template <typename TYPE, typename CB_TYPE>
  typename LazyContainer<TYPE, CB_TYPE>::iterator LazyContainer<TYPE, CB_TYPE>::begin ()
  { return iterator (cb); }

  template <typename TYPE, typename CB_TYPE>
  typename LazyContainer<TYPE, CB_TYPE>::iterator LazyContainer<TYPE, CB_TYPE>::end ()
  { return iterator (); }

  template <typename TYPE, typename CB_TYPE>
  int LazyContainer<TYPE, CB_TYPE>::size ()
  { return cb->size (); }

  template <typename TYPE, typename CB_TYPE>
  CB_TYPE* LazyContainer<TYPE, CB_TYPE>::get_cb ()
  { return cb; }

  template <typename TYPE, typename CB_TYPE>
  void LazyContainer<TYPE, CB_TYPE>::set_cb (CB_TYPE* icb)
  { cb = icb; }
};

#endif
